package com.hxs.hxsserver.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hxs.hxsserver.domain.dto.IdDTO;
import com.hxs.hxsserver.domain.dto.ResponseCode;
import com.hxs.hxsserver.domain.dto.device.*;
import com.hxs.hxsserver.domain.entity.device.Device;
import com.hxs.hxsserver.domain.entity.device.Factor;
import com.hxs.hxsserver.domain.entity.mode.RelayControlMode;
import com.hxs.hxsserver.domain.entity.relay.Relay;
import com.hxs.hxsserver.domain.entity.relay.RelayLog;
import com.hxs.hxsserver.domain.entity.user.User;
import com.hxs.hxsserver.enums.RelayModeEnums;
import com.hxs.hxsserver.exception.ApiException;
import com.hxs.hxsserver.mapper.device.FactorMapper;
import com.hxs.hxsserver.mapper.mode.RelayControlModeMapper;
import com.hxs.hxsserver.mapper.relay.RelayLogMapper;
import com.hxs.hxsserver.mapper.relay.RelayMapper;
import com.hxs.hxsserver.mapper.user.UserMapper;
import com.hxs.hxsserver.service.RelayService;
import com.hxs.hxsserver.service.SSEService;
import com.hxs.hxsserver.utils.ByteUtil;
import com.hxs.hxsserver.utils.CRCUtil;
import com.hxs.hxsserver.utils.DozerUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author liuchuan
 * @create 2024/10/8
 */
@Service
@Slf4j
public class RelayServiceImpl extends ServiceImpl<RelayMapper, Relay> implements RelayService {

    @Resource
    RelayMapper relayMapper;

    @Resource
    DozerUtil dozerUtil;

    @Resource
    SSEService  sseService;

    @Resource
    RelayLogMapper relayLogMapper;

    @Resource
    UserMapper userMapper;

    @Resource
    FactorMapper factorMapper;

    @Resource
    RelayControlModeMapper relayControlModeMapper;

    @Override
    public IPage<RelayDTO> getRelayList(QueryRelayListDTO queryRelayListDTO) {
        Page<FactorDTO> page = new Page<>(queryRelayListDTO.getPage(), queryRelayListDTO.getSize());
        return relayMapper.getRelayList(page,queryRelayListDTO);
    }

    @Override
    public Boolean updateRelay(RelayDTO relayDTO) {
        LambdaQueryWrapper<Relay> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Relay::getRelayNo,relayDTO.getRelayNo());
        queryWrapper.eq(Relay::getDeviceHardwareAddr,relayDTO.getDeviceHardwareAddr());
        queryWrapper.ne(Relay::getId, relayDTO.getId());
        Relay relay = relayMapper.selectOne(queryWrapper);
        //存在此编号
        if(relay!=null){
            throw new ApiException(ResponseCode.INSERT_RELAY_ERROR.getCode(), ResponseCode.INSERT_RELAY_ERROR.getDesc());
        }

        LambdaUpdateWrapper<Relay> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Relay::getId,relayDTO.getId());
        if (relayDTO.getDeviceHardwareAddr() != null) {
            updateWrapper.set(Relay::getDeviceHardwareAddr, relayDTO.getDeviceHardwareAddr());
        }
        if (relayDTO.getRelayNo() != null) {
            updateWrapper.set(Relay::getRelayNo, relayDTO.getRelayNo());
        }
        if (relayDTO.getEnable() != null) {
            updateWrapper.set(Relay::getEnable, relayDTO.getEnable());
        }
        if (relayDTO.getRelayName() != null) {
            updateWrapper.set(Relay::getRelayName, relayDTO.getRelayName());
        }
        if (relayDTO.getStatus() != null) {
            updateWrapper.set(Relay::getStatus, relayDTO.getStatus());
        }
        if (relayDTO.getWorkType() != null) {
            updateWrapper.set(Relay::getWorkType, relayDTO.getWorkType());
        }
        if (relayDTO.getWorkTime() != null) {
            updateWrapper.set(Relay::getWorkTime, relayDTO.getWorkTime());
        }
        this.update(updateWrapper);
        return true;
    }

    @Override
    public Boolean deleteRelay(IdDTO factorDTO) {
        int i = relayMapper.deleteById(factorDTO.getId());
        return true;
    }

    @Override
    public RelayDTO getRelayById(IdDTO idDTO) {
        Relay relay = relayMapper.selectById(idDTO);
        RelayDTO map = dozerUtil.map(relay, RelayDTO.class);
        return map;
    }

    @Override
    public Boolean insertRelay(RelayDTO relayDTO) {
        LambdaQueryWrapper<Relay> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Relay::getRelayNo,relayDTO.getRelayNo());
        queryWrapper.eq(Relay::getDeviceHardwareAddr,relayDTO.getDeviceHardwareAddr());
        Relay relay = relayMapper.selectOne(queryWrapper);
        if(relay!=null){
            throw new ApiException(ResponseCode.INSERT_RELAY_ERROR.getCode(), ResponseCode.INSERT_RELAY_ERROR.getDesc());
        }
        int insert = relayMapper.insert(dozerUtil.map(relayDTO, Relay.class));
        return true;
    }

    @Override
    public Boolean relayStatusManage(RelayManageDTO relayManageDTO,int userId) {

        RelayLog relayLog = new RelayLog();
        relayLog.setDeviceHardwareAddr(relayManageDTO.getDeviceHardwareAddr());
        User user = userMapper.selectById(userId);
        relayLog.setUserId(userId);
        relayLog.setUserName(user.getUserName());

        DeviceSSEDto deviceSSEDto = new DeviceSSEDto();
        deviceSSEDto.setDeviceHardwareAddr(relayManageDTO.getDeviceHardwareAddr());
        LambdaUpdateWrapper<Relay> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Relay::getDeviceHardwareAddr,relayManageDTO.getDeviceHardwareAddr());
        //继电器编号转16进制
        String no = ByteUtil.decimalToHex(relayManageDTO.getRelayNo());
        if (relayManageDTO.getStatus() != null && relayManageDTO.getStatus()) {
            LambdaQueryWrapper<Relay> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Relay::getRelayNo,relayManageDTO.getRelayNo());
            queryWrapper.eq(Relay::getDeviceHardwareAddr,relayManageDTO.getDeviceHardwareAddr());
            Relay relay = relayMapper.selectOne(queryWrapper);
            //单个继电器控制  单开
            String command = "5AA5"+relayManageDTO.getDeviceHardwareAddr()+"010504"+no+"01"+String.format("%04X", relay.getWorkTime());
            String crc = CRCUtil.crcRtu(ByteUtil.hexStringToByteArray(command));
            deviceSSEDto.setCommand(command + crc);
            updateWrapper.set(Relay::getStatus,relayManageDTO.getStatus());
            updateWrapper.eq(Relay::getRelayNo,relayManageDTO.getRelayNo());
            relayLog.setRelayNo(no);
            relayLog.setOperate("闭合");
        }else if(relayManageDTO.getStatus() != null && !relayManageDTO.getStatus()) {
            //单关
            String command ="5AA5"+relayManageDTO.getDeviceHardwareAddr()+"010504"+no+"000000";
            String crc = CRCUtil.crcRtu(ByteUtil.hexStringToByteArray(command));
            deviceSSEDto.setCommand(command + crc);
            updateWrapper.set(Relay::getStatus,relayManageDTO.getStatus());
            updateWrapper.eq(Relay::getRelayNo,relayManageDTO.getRelayNo());
            relayLog.setRelayNo(no);
            relayLog.setOperate("断开");
        }
        if(relayManageDTO.getAllStatus() != null && relayManageDTO.getAllStatus()){
            //全开
            String command = "5AA5"+relayManageDTO.getDeviceHardwareAddr()+"010620FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF";
            String crc = CRCUtil.crcRtu(ByteUtil.hexStringToByteArray(command));
            deviceSSEDto.setCommand(command + crc);
            updateWrapper.set(Relay::getStatus,1);
            relayLog.setRelayNo("所有");
            relayLog.setOperate("全开");
        }else if(relayManageDTO.getAllStatus() != null && !relayManageDTO.getAllStatus()){
            //全关
            String command = "5AA5"+relayManageDTO.getDeviceHardwareAddr()+"0106200000000000000000000000000000000000000000000000000000000000000000";
            String crc = CRCUtil.crcRtu(ByteUtil.hexStringToByteArray(command));
            deviceSSEDto.setCommand(command + crc);
            updateWrapper.set(Relay::getStatus,0);
            relayLog.setRelayNo("所有");
            relayLog.setOperate("全关");
        }
        relayLogMapper.insert(relayLog);
        Boolean command = sseService.command(deviceSSEDto);
        this.update(updateWrapper);
        return true;
    }

    @Override
    public IPage<RelayLog> getRelayLog(DeviceStatusQueryDTO deviceListQueryDTO) {
        Page<RelayLog> page = new Page<>(deviceListQueryDTO.getPage(), deviceListQueryDTO.getSize());
        return relayLogMapper.getRelayLog(page,deviceListQueryDTO);
    }

    @Override
    public Boolean insertRelayMode(RelayModeInsertReqDTO relayDTO, User user) {
            RelayControlMode relayControlMode = dozerUtil.map(relayDTO, RelayControlMode.class);
            DeviceSSEDto deviceSSEDto = new DeviceSSEDto();
            deviceSSEDto.setDeviceHardwareAddr(relayDTO.getDeviceHardwareAddr());
            if(relayDTO.getMode()== RelayModeEnums.AUTO.getCode()){
                planlimit(relayDTO);
                //自动模式计划
                Factor factor = factorMapper.selectById(relayDTO.getFactorId());
                relayControlMode.setFactorNodeNo(factor.getNodeNo());
                relayControlMode.setFactorSort(factor.getSort());
                relayControlMode.setCreateUserId(user.getId());
                relayControlModeMapper.insert(relayControlMode);
                //向继电器发消息
                sendmassage(relayDTO);
            }else if(relayDTO.getMode()== RelayModeEnums.FIXED_POINT.getCode()){
                planlimit(relayDTO);
                //定点模式计划
                relayControlModeMapper.insert(relayControlMode);
                //向继电器发消息
                sendmassage(relayDTO);
            }else if(relayDTO.getMode()== RelayModeEnums.WEEKLY.getCode()){
                planlimit(relayDTO);
                //星期模式计划
                relayControlModeMapper.insert(relayControlMode);
                //向继电器发消息
                sendmassage(relayDTO);
            }
            log.info("新增继电器计划成功");
            return true;
    }
    public void planlimit(RelayModeInsertReqDTO relayDTO){
        LambdaQueryWrapper<RelayControlMode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RelayControlMode::getRelayNo,relayDTO.getRelayNo());
        queryWrapper.eq(RelayControlMode::getDeviceHardwareAddr,relayDTO.getDeviceHardwareAddr());
        queryWrapper.eq(RelayControlMode::getMode,relayDTO.getMode());
        List<RelayControlMode> relayControlModes = relayControlModeMapper.selectList(queryWrapper);
        if(relayControlModes.size()>16){
            throw new ApiException(ResponseCode.RELAY_MODE_LIMIT_ERROR.getCode(), ResponseCode.RELAY_MODE_LIMIT_ERROR.getDesc());
        }else if(relayControlModes.size()>2 && relayDTO.getMode() == RelayModeEnums.AUTO.getCode()){
            throw new ApiException(ResponseCode.RELAY_AUTO_MODE_LIMIT_ERROR.getCode(), ResponseCode.RELAY_AUTO_MODE_LIMIT_ERROR.getDesc());
        }
    }
    //发送单个继电器的某个模式下的全量计划
    public void sendmassage(RelayModeInsertReqDTO relayDTO) {
        LambdaQueryWrapper<RelayControlMode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RelayControlMode::getRelayNo,relayDTO.getRelayNo());
        queryWrapper.eq(RelayControlMode::getDeviceHardwareAddr,relayDTO.getDeviceHardwareAddr());
        queryWrapper.eq(RelayControlMode::getMode,relayDTO.getMode());
        //根据定时任务时间点排序
        queryWrapper.orderByAsc(RelayControlMode::getScheduledTime);
        List<RelayControlMode> relayControlModes = relayControlModeMapper.selectList(queryWrapper);
        try {
            for (int i = 0; i < relayControlModes.size(); i++) {
                RelayControlMode relayControlMode1 = relayControlModes.get(i);
                DeviceSSEDto deviceSSEDto = new DeviceSSEDto();
                deviceSSEDto.setDeviceHardwareAddr(relayControlMode1.getDeviceHardwareAddr());
                //继电器编号转16进制
                String relayNo = ByteUtil.decimalToHex(relayControlMode1.getRelayNo());
                //继电器状态
                String relayStatus = ByteUtil.decimalToHex(relayControlMode1.getRelayStatus());
                if (relayDTO.getMode() == RelayModeEnums.AUTO.getCode()) {
                    //向继电器发消息
                    String beginHour = ByteUtil.decimalToHex(Integer.parseInt(relayControlMode1.getPeriodBeginTime().split(":")[0]));
                    String beginMin = ByteUtil.decimalToHex(Integer.parseInt(relayControlMode1.getPeriodBeginTime().split(":")[1]));
                    String endHour = ByteUtil.decimalToHex(Integer.parseInt(relayControlMode1.getPeriodEndTime().split(":")[0]));
                    String endMin = ByteUtil.decimalToHex(Integer.parseInt(relayControlMode1.getPeriodEndTime().split(":")[1]));
                    String factorNo = ByteUtil.decimalToHex(relayControlMode1.getFactorNodeNo());
                    String factorSort = ByteUtil.decimalToHex(relayControlMode1.getFactorSort());

                    String command = "5AA5" + relayControlMode1.getDeviceHardwareAddr() + "010710" + relayNo + relayStatus
                            + beginHour + beginMin + endHour + endMin + factorNo + factorSort
                            + relayControlMode1.getDataCondition() + String.format("%04X", relayControlMode1.getFactorDataBegin())
                            + String.format("%04X", relayControlMode1.getFactorDataEnd())
                            + String.format("%04X", relayControlMode1.getActorTime()) + ByteUtil.decimalToHex(relayControlModes.size());

                    String crc = CRCUtil.crcRtu(ByteUtil.hexStringToByteArray(command));
                    deviceSSEDto.setCommand(command + crc);
                }else if(relayDTO.getMode() == RelayModeEnums.FIXED_POINT.getCode()){
                    //向继电器发消息
                    String beginHour = ByteUtil.decimalToHex(Integer.parseInt(relayControlMode1.getScheduledTime().split(":")[0]));
                    String beginMins = ByteUtil.decimalToHex(Integer.parseInt(relayControlMode1.getScheduledTime().split(":")[1]));
                    String command = "5AA5"+relayControlMode1.getDeviceHardwareAddr()+"010809"+ relayNo + relayStatus + beginHour + beginMins
                            + String.format("%04X", relayControlMode1.getWorkTime()) + ByteUtil.decimalToHex(i) + "00" + ByteUtil.decimalToHex(relayControlModes.size());
                    String crc = CRCUtil.crcRtu(ByteUtil.hexStringToByteArray(command));
                    deviceSSEDto.setCommand(command + crc);
                }else if(relayDTO.getMode() == RelayModeEnums.WEEKLY.getCode()){
                    //向继电器发消息
                    String beginHour = ByteUtil.decimalToHex(Integer.parseInt(relayControlMode1.getScheduledTime().split(":")[0]));
                    String beginMins = ByteUtil.decimalToHex(Integer.parseInt(relayControlMode1.getScheduledTime().split(":")[1]));
                    String week = ByteUtil.decimalToHex(relayControlMode1.getWeek());
                    String command = "5AA5"+relayControlMode1.getDeviceHardwareAddr()+"010909"+ relayNo + relayStatus + beginHour + beginMins
                            + String.format("%04X", relayControlMode1.getWorkTime()) + ByteUtil.decimalToHex(i) + week + ByteUtil.decimalToHex(relayControlModes.size()) ;
                    String crc = CRCUtil.crcRtu(ByteUtil.hexStringToByteArray(command));
                    deviceSSEDto.setCommand(command + crc);
                }
                Boolean commandSent = sseService.command(deviceSSEDto);
            }
        } catch (ApiException e) {
            if(e.getCode()==ResponseCode.DEVICE_STATUS_ERROR.getCode()){
                log.info("设备不在线，计划命令发送失败");
            }
        }
    }

    @Override
    public List<RelayModeInsertReturnDTO> getRelayModeListByMode(QueryRelayModeListDTO queryRelayModeListDTO) {
        List<RelayModeInsertReturnDTO> relayModeInsertReturnDTOS = relayControlModeMapper.selectListByMode(queryRelayModeListDTO);
        return relayModeInsertReturnDTOS;
    }


    @Override
    public Boolean updateRelayModeById(RelayModeInsertReturnDTO relayDTO, User user) {
        RelayControlMode map = dozerUtil.map(relayDTO, RelayControlMode.class);
        int i = relayControlModeMapper.updateById(map);
        RelayControlMode relayControlMode = relayControlModeMapper.selectById(relayDTO.getId());
        //向继电器发消息
        RelayModeInsertReqDTO relayModeInsertReqDTO = dozerUtil.map(relayControlMode, RelayModeInsertReqDTO.class);
        sendmassage(relayModeInsertReqDTO);
        return true;
    }

    @Override
    public Boolean deleteRelayModeByIds(String ids) {
        String[] split = ids.split(",");
        //先查询出删除的是哪个模式的
        RelayControlMode relayControlMode = relayControlModeMapper.selectById(Integer.parseInt(split[0]));
        for (int i = 0; i < split.length; i++) {
            relayControlModeMapper.deleteById(Integer.parseInt(split[i]));
        }
        RelayModeInsertReqDTO relayModeInsertReqDTO = dozerUtil.map(relayControlMode, RelayModeInsertReqDTO.class);
        sendmassage(relayModeInsertReqDTO);
        return true;
    }
}
